<template>
  <div class="el-transfer">
    <transfer-panel
      v-bind="$props"
      :customFilter="leftcustomFilter"
      ref="leftPanel"
      class="left-panel"
      :data="sourceData"
      :loadDataNum="loadDataNum"
      :hasFooter="hasFooter"
      :title="titles[0] || '列表 1'"
      :default-checked="leftDefaultChecked"
      :placeholder="filterPlaceholder || '请输入搜索内容'"
      @onCheckedChange="onSourceCheckedChange"
    >
      <slot name="left-footer"></slot>
      <template v-slot:leftCustomFilter>
        <slot name="leftCustomFilter"></slot>
      </template>
    </transfer-panel>
    <div class="el-transfer__buttons" :class="buttonsClass">
      <el-button
        type="primary"
        :class="['el-transfer__button', hasButtonTexts ? 'is-with-texts' : '']"
        @click="addToLeft"
        :disabled="rightChecked.length === 0"
      >
        <span v-if="buttonTexts[0] !== undefined">{{ buttonTexts[0] }}</span>
      </el-button>
      <el-button
        type="primary"
        :class="['el-transfer__button', hasButtonTexts ? 'is-with-texts' : '']"
        @click="addToRight"
        :disabled="leftChecked.length === 0"
      >
        <span v-if="buttonTexts[1] !== undefined">{{ buttonTexts[1] }}</span>
      </el-button>
    </div>
    <transfer-panel
      v-bind="$props"
      :customFilter="false"
      ref="rightPanel"
      :data="targetData"
      :loadDataNum="loadDataNum"
      :hasFooter="hasFooter"
      :title="titles[1] || '列表 2'"
      :default-checked="rightDefaultChecked"
      :placeholder="filterPlaceholder || '请输入搜索内容'"
      @onCheckedChange="onTargetCheckedChange"
    >
      <slot name="right-footer"></slot>
    </transfer-panel>
  </div>
</template>

<script lang="ts">
import { computed, defineComponent, reactive, watch, getCurrentInstance, toRefs } from 'vue'
import TransferPanel from './transfer-panel.vue'
export default defineComponent({
  name: 'V7Transfer',
  components: {
    TransferPanel
  },
  props: {
    data: {
      type: Array,
      default: () => []
    },
    titles: {
      type: Array,
      default: () => []
    },
    buttonTexts: {
      type: Array,
      default: () => []
    },
    filterPlaceholder: {
      type: String,
      default: ''
    },
    leftDefaultChecked: {
      type: Array,
      default: () => []
    },
    rightDefaultChecked: {
      type: Array,
      default: () => []
    },
    modelValue: {
      type: Array,
      default: () => []
    },
    leftcustomFilter: {
      type: Boolean
    },
    props: {
      type: Object,
      default: () => ({
        label: 'label',
        key: 'key',
        disabled: 'disabled'
      })
    },
    targetOrder: {
      type: String,
      default: 'original'
    },
    loadDataNum: {
      type: Number,
      default: 20
    },
    buttonsClass: {
      type: String,
      default: ''
    },
    filterable: {
      type: Boolean
    },
    filterMethod: {},
    customFilterMethod: {},
    leftcustomFilterData: {},
    renderContent: {},
    format: {
      type: Array,
      default: () => []
    },
    hasFooter: {
      type: Boolean,
      default: false
    }
  },
  emits: ['onLeftCheckChange', 'onRightCheckChange', 'onInput', 'onChange', 'update:modelValue'],
  setup(props, { emit }) {
    const instance = getCurrentInstance()
    const state = reactive({
      leftChecked: [],
      rightChecked: [],
      allDataObj: {} as any
    })

    const dataObj: any = computed(() => {
      const key = props.props.key
      return props.data.reduce((o: any, cur: any) => (o[cur[key]] = cur) && o, {})
    })

    const sourceData = computed(() => {
      console.log(
        props.data.filter((item: any) => props.modelValue.indexOf(item[props.props.key]) === -1),
        'data'
      )
      return props.data.filter((item: any) => props.modelValue.indexOf(item[props.props.key]) === -1)
    })

    const targetData = computed(() => {
      if (props.targetOrder === 'original') {
        if (!Object.keys(state.allDataObj).length) {
          handleData()
        }
        const targetArr: any = []
        props.modelValue.forEach((item: any) => {
          if (state.allDataObj[item]) {
            targetArr.push(state.allDataObj[item])
          }
        })
        return targetArr
      } else {
        return props.modelValue.reduce((arr: any, cur: any) => {
          const val = dataObj.value[cur]
          if (val) {
            arr.push(val)
          }
          return arr
        }, [])
      }
    })

    const hasButtonTexts = computed(() => {
      return props.buttonTexts.length === 2
    })

    watch(
      () => props.modelValue,
      (newVal: any) => {
        dispatch('ElFormItem', 'el.form.change', newVal)
      }
    )

    const getMigratingConfig = () => {
      return {
        props: {
          'footer-format': 'footer-format is renamed to format.'
        }
      }
    }

    const handleData = () => {
      props.data.forEach((item: any) => {
        state.allDataObj[item[props.props.key]] = item
      })
    }

    const onSourceCheckedChange = (val: any, movedKeys: any) => {
      state.leftChecked = val
      if (movedKeys === undefined) {
        return
      }
      emit('onLeftCheckChange', val, movedKeys)
    }

    const onTargetCheckedChange = (val: any, movedKeys: any) => {
      state.rightChecked = val
      if (movedKeys === undefined) {
        return
      }
      emit('onRightCheckChange', val, movedKeys)
    }

    const addToLeft = () => {
      const currentValue = props.modelValue.slice()
      state.rightChecked.forEach((item: any) => {
        const index = currentValue.indexOf(item)
        if (index > -1) {
          currentValue.splice(index, 1)
        }
      })
      emit('update:modelValue', currentValue)
      emit('onInput', currentValue)
      emit('onChange', currentValue, 'left', state.rightChecked)
    }

    const addToRight = () => {
      let currentValue = props.modelValue.slice()
      const itemsToBeMoved: any = []
      const key = props.props.key
      const leftCheckedKeyPropsObj: any = {}
      state.leftChecked.forEach((item: any) => {
        leftCheckedKeyPropsObj[item] = true
      })
      const valueKeyPropsObj: any = {}
      props.modelValue.forEach((item: any) => {
        valueKeyPropsObj[item] = true
      })
      props.data.forEach((item: any) => {
        const itemKey = item[key]
        if (leftCheckedKeyPropsObj[itemKey] && !valueKeyPropsObj[itemKey]) {
          itemsToBeMoved.push(itemKey)
        }
      })
      currentValue =
        props.targetOrder === 'unshift' ? itemsToBeMoved.concat(currentValue) : currentValue.concat(itemsToBeMoved)
      emit('update:modelValue', currentValue)
      emit('onInput', currentValue)
      emit('onChange', currentValue, 'right', state.leftChecked)
    }

    const dispatch = (componentName: any, eventName: any, params: any) => {
      let parent: any = instance?.parent || instance?.root
      let name = parent.type.name
      while (parent && (!name || name !== componentName)) {
        parent = parent.parent
        if (parent) {
          name = parent.type.name
        }
      }
      if (parent) {
        parent.emit.apply(parent, [eventName].concat(params))
      }
    }

    return {
      ...toRefs(state),
      sourceData,
      targetData,
      hasButtonTexts,
      onSourceCheckedChange,
      onTargetCheckedChange,
      addToLeft,
      addToRight,
      getMigratingConfig
    }
  }
})
</script>
<style lang="stylus" scoped>
.el-transfer__button
  display block
.el-button+.el-button
  margin-left 0px
.el-button [class*=el-icon-]+span
  margin-left 0px
.el-transfer__button:first-child
  margin-bottom 10px
.el-transfer-panel
  width 300px
  .el-transfer-panel__header .el-checkbox .el-checkbox__label
    font-size 14px
  .el-form-item__label
    color #767e92
    font-size 12px
  .el-transfer-panel__item
    margin 10px 10px 10px 0px
  .el-transfer-panel__item.el-checkbox .el-checkbox__label
    font-size 12px
  .el-transfer__button i, .el-transfer__button span
    font-size 12px
:deep(.el-transfer-panel__filter)
  text-align: center;
  margin: 15px;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  display: block;
  width: auto
  .el-input__wrapper
    height: 32px
    width: -webkit-fill-available
    font-size: 12px
    border-radius: 16px
    padding-right 30px
    padding-left 20px
</style>
